//
//  Modelo_Tablero.cpp
//  PEI
//
//  Created by asc on 04/04/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#include <iostream>
#include <string>
#include "Modelo.h"
#include "Modelo_Tablero.h"

/*
 * CODE_TABLERO
 */


tablero::tablero(int tam, int mode, bool aleatorio): Modelo(), mod(mode)
{
    rows = tam;
    nitems = rows*rows;
    table.insert(table.begin(),nitems, casilla());
    enlazaCasillas(aleatorio);
    generacion=0;
}

tablero::tablero(string fichero, int mode):Modelo(),mod(mode)
{
    ifstream Entrada;
    Entrada.open(fichero.c_str(), ios::in);
    if(!Entrada.is_open())
    {
        cerr << "FileNotOpen\n";
        rows = 0;
    }
    else
    {
        string linea ="";
        getline(Entrada,linea);

        rows=linea.length();
        nitems = rows*rows;
        table.insert(table.begin(),nitems, casilla());
        enlazaCasillas(false);
        generacion=0;

        for(int i=0; i<rows; i++)
        {
            for(int j=0; j<rows; j++)
            {
                if(getEstado(i,j) == true && linea[j]=='0')cambiaEstado(i,j);
                else if(getEstado(i,j) == false && linea[j]=='1')cambiaEstado(i,j);
            }
            linea="";
            getline(Entrada,linea);
        }
    }
}

tablero::~tablero()
{
    table.clear();
}


void tablero::guarda(string fichero)
{
    int i=0;
    string salida="";
    for (vector<casilla>::iterator it= table.begin(); it!=table.end(); ++it,++i) {
        salida += ((i%rows == 0 && i!=0)?"\n": ""); salida += ((it->getEstado())? "1":"0");
    }

    salida +="\n";

    ofstream fSalida;
    fSalida.open(fichero.c_str(), ios::out);
    if(!fSalida.is_open()) cerr << "FileNotOpen\n";
    else fSalida << salida;
}

void tablero::siguienteEtapaNodo(vector<casilla>::iterator it)
{
    int nActivos = 0;
    vector<casilla*> adyacente = it->getAdyacentes();
    for (vector<casilla*>::iterator it2 = adyacente.begin(); it2!=adyacente.end(); ++it2) {
        if ((*it2)->getEstado()) {
            nActivos++;
        }
    }
    //cerr << nActivos << "\t";
    if(it->getEstado())it->setSiguiente(mod.debeMorir(nActivos));
    else it->setSiguiente(mod.debeNacer(nActivos));
}

void tablero::actualizaNodo(vector<casilla>::iterator it)
{
    it->Actualiza();
}

void tablero::calculaSiguienteEtapa()
{
    int i=0;
    for (it=table.begin(); it!=table.end(); ++it, i++) {
        siguienteEtapaNodo(it);
    }
    for (it=table.begin(); it!=table.end(); ++it) {
        actualizaNodo(it);
    }
    generacion++;
    actualizar_vistas();
}

void tablero::enlazaCasillas(bool aleatorio)
{
    int i=0;
    for (vector<casilla>::iterator it=table.begin(); it!=table.end(); ++it, i++) {
        vector<casilla*> adyacencia;

        if(i%rows == 0){
            if (i-rows < 0) {
                //cerr << "casilla " << i << "primera columna primera linea"<< endl;
                adyacencia.push_back(&table[i+rows]);
                adyacencia.push_back(&table[i+rows+1]);
            }
            else if ((i+rows) >= nitems) {
                //cerr << "casilla " << i << "primera columna ultima linea"<< endl;
                adyacencia.push_back(&table[i-rows]);
                adyacencia.push_back(&table[i-rows+1]);
            }
            else {
                //cerr << "casilla " << i << "primera columna resto linea"<< endl;
                adyacencia.push_back(&table[i-rows]);
                adyacencia.push_back(&table[i-rows+1]);
                adyacencia.push_back(&table[i+rows]);
                adyacencia.push_back(&table[i+rows+1]);
            }
            adyacencia.push_back(&table[i+1]);
        }
        else if ((i+1)%rows == 0) {
            if (i-rows < 0) {
                //cerr << "casilla " << i << "ultima columna primera linea"<< endl;
                adyacencia.push_back(&table[i+rows]);
                adyacencia.push_back(&table[i+rows-1]);
            }
            else if ((i+rows) >= nitems) {
                //cerr << "casilla " << i << "ultima columna ultima linea"<< endl;
                adyacencia.push_back(&table[i-rows]);
                adyacencia.push_back(&table[i-rows-1]);
            }
            else {
                //cerr << "casilla " << i << "ultima columna resto linea"<< endl;
                adyacencia.push_back(&table[i-rows]);
                adyacencia.push_back(&table[i-rows-1]);
                adyacencia.push_back(&table[i+rows]);
                adyacencia.push_back(&table[i+rows-1]);
            }
            adyacencia.push_back(&table[i-1]);
        }
        else {
            if (i-rows < 0) {
                //cerr << "casilla " << i << "resto columna primera linea"<< endl;
                adyacencia.push_back(&table[i+rows]);
                adyacencia.push_back(&table[i+rows-1]);
                adyacencia.push_back(&table[i+rows+1]);
            }
            else if ((i+rows) >= nitems) {
                //cerr << "casilla " << i << "resto columna ultima linea"<< endl;
                adyacencia.push_back(&table[i-rows]);
                adyacencia.push_back(&table[i-rows+1]);
                adyacencia.push_back(&table[i-rows-1]);
            }
            else {
                //cerr << "casilla " << i << "resto columna resto linea"<< endl;
                adyacencia.push_back(&table[i+rows]);
                adyacencia.push_back(&table[i+rows+1]);
                adyacencia.push_back(&table[i+rows-1]);
                adyacencia.push_back(&table[i-rows]);
                adyacencia.push_back(&table[i-rows-1]);
                adyacencia.push_back(&table[i-rows+1]);
            }
            adyacencia.push_back(&table[i-1]);
            adyacencia.push_back(&table[i+1]);
        }
        it->setCasillas(adyacencia);
        if(i==0)srand(time(NULL));
        //cerr << rand()<< endl;
        if(aleatorio && rand() < 1000000000)it->setEstado(true);
    }
}

int tablero::getGeneracion()
{
    return generacion;
}

int tablero::getRows()
{
    return rows;
}

int tablero::getNItems()
{
    return nitems;
}

variantes* tablero::getVariante()
{
    return &mod;
}

vector<casilla> tablero::getTablero()
{
    return table;
}

void tablero::cambiaEstado(int i, int j)
{
    int posCasilla = i*rows + j;
    vector<casilla>::iterator it = table.begin() + posCasilla;
    it->setEstado(!it->getEstado());
}

bool tablero::getEstado(int i, int j)
{
    int posCasilla = i*rows + j;
    vector<casilla>::iterator it = table.begin() + posCasilla;
    return it->getEstado();
}

void tablero::cambiaVariante(int i)
{
    mod.setVariante(i);
}
